﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Fortuitus.Core
{
    public static class EnumerableOfDoubleExtensions
    {
        /// <summary>
        /// Turns an enumeration of doubles into a Vector.
        /// </summary>
        /// <param name="enumeration">An enumration of doubles.</param>
        /// <returns>The resulting Vector.</returns>
        public static Vector ToVector(this IEnumerable<double> enumeration)
        {
            Vector vector = new Vector(enumeration);
            return vector;
        }

        /// <summary>
        /// Turns an enumeration of doubles into an EditableVector.
        /// </summary>
        /// <param name="enumeration">An enumration of doubles.</param>
        /// <returns>The resulting EditableVector.</returns>
        public static Vector ToEditableVector(this IEnumerable<double> enumeration)
        {
            EditableVector vector = new EditableVector(enumeration);
            return vector;
        }

        /// <summary>
        /// Checks whether an enumeration of doubles is empty or just contains missing values (NaN).
        /// </summary>
        /// <param name="vector">The input enumartion of numbers.</param>
        /// <returns>An value indicating whether the enumeratin is empty or consists of missing values only.</returns>
        public static bool IsEmptyOrHasNoValues(this IEnumerable<double> vector)
        {
            bool hasValues = false;
            foreach (double number in vector)
            {
                if (!double.IsNaN(number))
                {
                    hasValues = true;
                }
            }
            return hasValues;
        }

        /// <summary>
        /// Calculates the arithmetic mean of an enumartion of doubles and ignores missing values (NaN).
        /// </summary>
        /// <param name="vector">The input enumartion of doubles.</param>
        /// <returns>The arithmetic mean of the numbers from the input.</returns>
        public static double Mean(this IEnumerable<double> vector)
        {
            double sum = 0;
            int count = 0;
            foreach (double number in vector)
            {
                if (!double.IsNaN(number))
                {
                    count++;
                    sum += number;
                }
            }
            if (count == 0)
                throw new ArgumentException("The input doesn't contain any non-MissingValues.", "vector");

            double mean = sum / count;
            return sum / count;
        }

        /// <summary>
        /// Calculates the variance of an enumeration of numbers and ignores missing values (NaN).
        /// </summary>
        /// <param name="vector">The input enumeration of numbers.</param>
        /// <returns>The variance the numbers from the input.</returns>
        public static double Variance(IEnumerable<double> vector)
        {
            double variance = 0;
            double count = 0;
            double diffs = 0;
            double mean = Mean(vector);

            foreach (double number in vector)
            {
                if (!double.IsNaN(number)) //only process non-NaN values
                {
                    diffs += (number - mean) * (number - mean);
                    count++;
                }
            }
            variance = diffs / (count);
            return variance;
        }
    }
}
